
#include <iostream>
#include "assert.h"

#include "../../Libs/TXLib.h"
#include "VectorExceptions.h"

#define ADD_EXC_DATA __PRETTY_FUNCTION__, __LINE__

const int MAX_SIZE = 10;

template<class Type>
class Array2D;

template<class Type>
class InnerArray
{
    private:
        Type (*data_)[MAX_SIZE][MAX_SIZE];
        int first_value_;

    public:

        int width_;
        int height_;

        InnerArray(Type (*data)[MAX_SIZE][MAX_SIZE], int first_value, int width, int height):
            data_(data),
            first_value_(first_value),
            width_(width),
            height_(height)

            {}

        Type& operator[] (int index)
        {
            //cout << "I came to final step!\n";

            if(index < 0 || index >= height_) throw IndexFaultException(ADD_EXC_DATA, index, height_);

            return (*data_)[first_value_][index];
        }
};

template<class Type>
class Array2D //Allocator2D
{
    private:
        Type data_[MAX_SIZE][MAX_SIZE];
        int width_;
        int height_;
        //int* counter_;

    public:
        Array2D();
        Array2D(int width, int height);

        int width() { return width_; }
        int height() { return height_; }

        bool ok() { return (width() >= 0 || height() >= 0); }
        void dump();

        InnerArray<Type> operator[] (int index)
        {
            if(index < 0 || index >= width()) throw IndexFaultException(ADD_EXC_DATA, index, width());

            return InnerArray<Type>(&data_, index, width(), height());
        }
        //Allocator2D(const Allocator2D& that) explicit;

        //It is static... But I wanted to do copy constructor

        //void AddRef()  { assert(counter_); (*counter_)++; }
        //void Release() { assert(counter_); (*counter_)--; }

        //const Allocator2D& operator = (const Allocator2D& that);
};

template<class Type>
Array2D<Type>::Array2D():

    width_(0),
    height_(0)
    //counter_(new int(1))

    {}

template<class Type>
Array2D<Type>::Array2D(int width, int height):

    width_(width),
    height_(height)
    //counter_(new int(1))

    {
        if(width  > MAX_SIZE) throw SizeFaultException(ADD_EXC_DATA, width);
        if(height > MAX_SIZE) throw SizeFaultException(ADD_EXC_DATA, height);

        for(int i = 0; i < width; i++)
        {
            for(int j = 0; j < height; j++)
            {
                if(i < 0 || i >= width) throw IndexFaultException(ADD_EXC_DATA, i, width);
                if(j < 0 || j >= height) throw IndexFaultException(ADD_EXC_DATA, j, height);

                data_[i][j] = ZERO(Type);
            }
        }
    }

template<class Type>
void Array2D<Type>::dump()
{
    cout << "Array2D dump was called!\n";
    cout << "    Width: " << width() << std::endl;
    cout << "    Height: " << height() << std::endl;
    cout << "    Status: " << ok() << std::endl << std::endl;

    for(int i = 0; i < width(); i++)
    {
        cout << "    " << i << " element contains: { ";

        for(int j = 0; j < height(); j++)
        {
            assert(i >= 0); assert(i < width());
            assert(j >= 0); assert(j < height());

            cout << data_[i][j] << " ";
        }

        cout << "}\n";
    }
}

//Allocator2D::Allocator2D(const Allocator2D& that):

//    data_(that.data_),
//    width_(that.width_),
//    height_(that.height_)

//    {
//        AddRef();
//    }
